package com.libnetwork.httpservice

import okhttp3.MediaType
import okhttp3.Response
import okhttp3.ResponseBody
import okio.*
import java.io.IOException

class DownloadResponseBody(
    private val originalResponse: Response,
    val startsPoint: Long = 0,
    var progress: (progress: DownloadProgress) -> Unit
) : ResponseBody() {
    private var source: BufferedSource = source(originalResponse.body?.source() ?: throw NullPointerException("source == null"))
        .buffer()

    override fun contentType(): MediaType? {
        return originalResponse.body?.contentType()
    }

    override fun contentLength(): Long {
        return originalResponse.body?.contentLength() ?: 0
    }

    override fun source(): BufferedSource {
        return source
    }

    private fun source(source: Source): Source {
        return object : ForwardingSource(source) {
            private var totalBytesRead: Long = startsPoint

            @Throws(IOException::class)
            override fun read(sink: Buffer, byteCount: Long): Long {
                val bytesRead = super.read(sink, byteCount)

                totalBytesRead += if (bytesRead == -1L) 0 else bytesRead

                val contentLength: Long = contentLength()
                if (contentLength == 0L) {
                    progress(
                        DownloadProgress(
                            1.0,
                            contentLength,
                            totalBytesRead,
                            bytesRead == -1L,
                            null,
                            null
                        )
                    )
                } else {
                    progress(
                        DownloadProgress(
                            totalBytesRead / contentLength.toDouble(),
                            contentLength,
                            totalBytesRead,
                            bytesRead == -1L,
                            null,
                            null
                        )
                    )
                }

                return bytesRead
            }
        }
    }
}